package com.librariy.net;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;

import androidx.lifecycle.MutableLiveData;

import com.librariy.json.JsonObject;
import com.librariy.util.Log;

public class HttpClient {
    public final static String TAG = "HttpClientLibrary";
    protected final static Handler mMainHandler = new Handler(Looper.getMainLooper());;
    protected final static ExecutorService threadPool= new ThreadPoolExecutor(0, 5,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
    public static void proxy(String host,int port) {
        System.setProperty("http.proxyHost", host);
        System.setProperty("http.proxyPort", port+"");
    }
    public static void request(final HttpRequest request, final HttpResponse callback) {
        threadPool.execute(()->{
            HttpResult result=HttpClient.requestSync(request);
            mMainHandler.post(() -> callback.onCompleted(result.responseCode, result.responseText));
        });
    }

    public static MutableLiveData<HttpResult> request(final HttpRequest request) {
        MutableLiveData<HttpResult> liveData = new MutableLiveData<>();
        threadPool.execute(()->{
            liveData.postValue(HttpClient.requestSync(request));
        });
        return liveData;
    }

    /**
     * @param request
     * @return HttpResult-该参数永不为空，可以放心使用。
     */
    public static HttpResult requestSync(final HttpRequest request) {
        HttpResult result;
        if (request.method == HttpRequest.Method.POST_BIN) {
            result = requestHttpAsBinary(request);
        } else {
            result = requestHttpAsText(request);
        }
        Log.i(TAG, "" + result);
        return result;
    }

    /**
     * Http文本请求
     * 
     * @param request
     * @return HttpResult
     */
    private static HttpResult requestHttpAsText(HttpRequest request) {
        try {
            request.onBackgroundInitialize();
            request.checkBeforeRequest();
            Log.i(TAG, ""+request);
            //Log.i(TAG, "encodeURI=" + request.getFinalUrl("UTF-8"));
            HttpURLConnection conn = (HttpURLConnection) (new URL(request.getFinalUrl("UTF-8"))).openConnection();
            SSLManager.initSSL(conn);
            conn.setRequestMethod(request.getHttpMethod());
            conn.setConnectTimeout(30 * 1000);
            conn.setReadTimeout(30 * 1000);
            conn.setDoInput(true);

            for (HttpRequest.FieldItem item : request.headers) {
                conn.setRequestProperty(item.fieldName, (String) item.fieldValue);
            }
            byte[] bodyData=request.getBody("UTF-8");
            if (bodyData!=null) {
                conn.setDoOutput(true);
                OutputStream requestOut = conn.getOutputStream();
                requestOut.write(bodyData);
                requestOut.flush();
                requestOut.close();
            }
            // 读取返回数据
            ByteArrayOutputStream responseOut = new ByteArrayOutputStream();
            int mResponseCode = conn.getResponseCode();
            String mContentType = conn.getContentType();
            BufferedInputStream responseIn = HttpClient.getInputStream(mResponseCode, conn);
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = responseIn.read(buff)) > 0) {
                responseOut.write(buff, 0, len);
            }
            responseIn.close();
            return new HttpResult(mResponseCode, mContentType, responseOut.toString("UTF-8"));
        } catch (UnsupportedOperationException e) {
            e.printStackTrace();
            return new HttpResult(-2, "text/plain; charset=utf-8", e.getMessage());
        } catch (Exception e) {
            Log.e(TAG, "请求出错", e);
            return new HttpResult(-1, "text/plain; charset=utf-8", "请求出错");
        }
    }

    /**
     * Http二进制请求
     * 
     * @param request
     * @return HttpResult
     */
    private static HttpResult requestHttpAsBinary(HttpRequest request) {
        String BOUNDARY = "---------------------------123821742118716"; // boundary就是request头和上传文件内容的分隔符
        try {
            request.onBackgroundInitialize();
            request.checkBeforeRequest();
            request.setHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            Log.i(TAG, "" + request);
            HttpURLConnection conn = (HttpURLConnection) (new URL(request.getFinalUrl("UTF-8"))).openConnection();

            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);
            conn.setChunkedStreamingMode(100 * 1024);
            // conn.setReadTimeout(10000);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            for (HttpRequest.FieldItem item : request.headers) {
                conn.setRequestProperty(item.fieldName, (String) item.fieldValue);
            }
            // text
            if (request.bodyFields != null) {
                conn.setDoOutput(true);
                OutputStream requestOut = conn.getOutputStream();
                int len = request.bodyFields.size();
                for (int i = 0; i < len; i++) {
                    HttpRequest.FieldItem item = request.bodyFields.get(i);
                    item.writeBodyPart(requestOut, BOUNDARY);
                }
                requestOut.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
                requestOut.flush();
                requestOut.close();
            }
            // 读取返回数据
            ByteArrayOutputStream responseOut = new ByteArrayOutputStream();
            int mResponseCode = conn.getResponseCode();
            String mContentType = conn.getContentType();
            BufferedInputStream responseIn = HttpClient.getInputStream(mResponseCode, conn);
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = responseIn.read(buff)) > 0) {
                responseOut.write(buff, 0, len);
            }
            responseIn.close();
            return new HttpResult(mResponseCode, mContentType, responseOut.toString("UTF-8"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return new HttpResult(-3, "text/plain; charset=utf-8", "上传的文件不存在");
        } catch (UnsupportedOperationException e) {
            e.printStackTrace();
            return new HttpResult(-2, "text/plain; charset=utf-8", e.getMessage());
        } catch (Exception e) {
            Log.e(TAG, "服务器连接异常，请检查网络", e);
            return new HttpResult(-1, "text/plain; charset=utf-8", "服务器连接异常，请检查网络");
        }
    }

    private static BufferedInputStream getInputStream(int mResponseCode, HttpURLConnection conn) {
        try {
            InputStream retIn = conn.getErrorStream();
            if (retIn != null)
                return new BufferedInputStream(retIn);
            retIn = conn.getInputStream();
            if (retIn != null)
                return new BufferedInputStream(retIn);
            Log.i(TAG, String.format("[%s]服务器无返回数据(D)", mResponseCode));
            return new BufferedInputStream(new ByteArrayInputStream(new byte[0]));
        } catch (Exception e) {
            Log.i(TAG, String.format("[%s]服务器无返回数据(E)", mResponseCode));
            return new BufferedInputStream(new ByteArrayInputStream(new byte[0]));
        }
    }

    public static class HttpResult {
        public final int responseCode;
        public final String mContentType;
        public final String responseText;

        public HttpResult(int responseCode, String mContentType, String responseText) {
            this.responseCode = responseCode;
            this.mContentType = mContentType == null ? "" : mContentType;
            this.responseText = responseText == null ? "" : responseText;
        }

        @Override
        public String toString() {
            return String.format("[HttpResult]: responseCode=%s,  mContentType=%s\n%s", responseCode,mContentType, responseText);
        }
    }
}